﻿
using System.IO;
using System;
namespace Framework.Extensions
{
    /// <summary>
    /// Extension methods for stream.
    /// </summary>
    public static class StreamExtensions
    {
        /// <summary>
        /// Copies the specified input stream.
        /// </summary>
        /// <param name="source">The source stream.</param>
        /// <param name="target">The output stream.</param>
        public static void CopyStream(this Stream source, Stream target)
        {
            var srcPos = (source.CanSeek ? source.Position : long.MinValue);
            var destPos = (target.CanSeek ? target.Position : long.MinValue);

            const int bufSize = 0x1000;
            var buf = new byte[bufSize];
            int bytesRead;
            while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)
            {
                target.Write(buf, 0, bytesRead);
            }

            var targetAsMemStream = target as MemoryStream;
            if (targetAsMemStream != null)
                targetAsMemStream.Capacity = Convert.ToInt32(targetAsMemStream.Length);

            if (target.CanSeek)
                target.Position = destPos;

            if (source.CanSeek)
                source.Position = srcPos;
        }

        /// <summary>
        /// Loads the specified stream into memory stream.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static MemoryStream LoadIntoMemoryStream(this Stream source)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            if (!source.CanRead)
                throw new ArgumentException("source cannot be read (write only?)", "source");

            var initialCapacity = 32768;
            try
            {
                var templateSize = source.Length;
                initialCapacity = Convert.ToInt32(templateSize);
            }
            catch (NotSupportedException)
            {
            }

            var memStream = new MemoryStream(initialCapacity);
            source.CopyStream(memStream);
            return memStream;
        }


        public static void SaveAs(this Stream stream, string path)
        {
            File.WriteAllBytes(path, stream.ToByteArray());
        }

        /// <summary>
        /// Converts a stream into a byte array.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <returns></returns>
        public static byte[] ToByteArray(this Stream stream)
        {
            long originalPosition = stream.Position;
            stream.Position = 0;

            try
            {
                byte[] readBuffer = new byte[4096];

                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                stream.Position = originalPosition;
            }
        }

    }
}